//# sourceURL=http://uMapApp/Earth/ViewShed
define([
    "mhjs/mhjs",
    "uMap/uMap",
    "uEarth/uEarth"
], function (
    mhjs,
    uMap,
    uEarth
) {

    function ViewShed(option) {

        var _this = this;

        if (option && option.earth) {

            _this.earth = option.earth;
            _this._camera = new uEarth.Camera(_this.earth.scene);

            _this.shadowMap = new uEarth.ShadowMap({
                context         : _this.earth.scene.context,
                lightCamera     : _this.camera,
                enabled         : _this.isOpened || true,
                isPointLight    : true,
                pointLightRadius: _this.camera.frustum.far,
                cascadesEnabled : false,
                size            : 2048,
                softShadows     : true,
                normalOffset    : false,
                fromLightSource : false
            });

            // _this.earth.scene.shadowMap = _this.shadowMap;


            _this._cameraPosition = option.cameraPosition && new uMap.Position(option.cameraPosition);
            _this._cameraPositionEnd = option.cameraPositionEnd && new uMap.Position(option.cameraPositionEnd);

            // _this._cameraDistance = _this._cameraPositionEnd ? uEarth.Cartesian3.distance(_this._cameraPosition, _this._cameraPositionEnd) : (option.cameraDistance || 100.0);


            _this._cameraViewHeading = _this._cameraPositionEnd ? uMap.Positions.getHeading(_this._cameraPosition, _this._cameraPositionEnd) : (option.cameraViewHeading || 0.0);
            _this._cameraViewPitch = _this._cameraPositionEnd ? uMap.Positions.getPitch(_this._cameraPosition, _this._cameraPositionEnd) : (option.cameraViewPitch || 0.0);

            _this._cameraHorizontalViewAngle = option.cameraHorizontalViewAngle || 90.0;
            _this._cameraVerticalViewAngle = option.cameraVerticalViewAngle || 60.0;

            _this._camera.frustum.near = 0.001;
            _this._camera.frustum.far = 5000;

            _this.updateCamera();


            _this.visibleAreaColor = option.visibleAreaColor || uEarth.Color.GREEN;
            _this.invisibleAreaColor = option.invisibleAreaColor || uEarth.Color.RED;

            _this.textureType = _class.TEXTURE_TYPE[option.textureType] || _class.TEXTURE_TYPE.IMAGE;
            _this.textureUrl = option.textureUrl;
            _this.alpha = option.alpha || 0.5;

        }

    }

    var _class = ViewShed;

    Object.defineProperties(_class.prototype, {
        open                     : {
            value: function () {

                var _this = this;

                if (!_this.isOpened) {

                    _this.load(function () {

                        _this.loadTexture(function () {
                            _this.addPostStageListener();
                            _this.addFrustumOutline();

                            _this.isOpened = true;

                            _this.trigger("open");
                        });


                    });

                }

            }
        },
        close                    : {
            value: function () {

                var _this = this;

                if (_this.isOpened) {

                    _this.removePostStageListener();
                    _this.removeFrustumOutline();
                    _this.removeTexture();

                    _this.isOpened = false;

                    _this.trigger("close");
                }
            }
        },
        load                     : {
            value: function (callback) {

                var _this = this;

                if (!_this.isLoaded) {

                    $.get("./js/App/Earth/ViewShed.glsl", function (glsl) {
                        _this.glsl = glsl;
                        _this.isLoaded = true;
                        callback && callback();
                    });

                } else {
                    callback && callback();
                }


            }
        },
        camera                   : {
            get: function () {
                var _this = this;
                return _this._camera;
            }
        },
        cameraPosition           : {
            get: function () {
                var _this = this;
                return _this._cameraPosition;
            },
            set: function (position) {
                var _this = this;

                if (position) {
                    _this._cameraPosition = position;
                    _this._camera.position = new uMap.Position(_this.cameraPosition);
                    _this.updateCamera();
                }
            }
        },
        cameraPositionEnd        : {
            get: function () {
                var _this = this;
                return _this._cameraPositionEnd;
            },
            set: function (position) {
                if (position) {
                    var _this = this;
                    _this._cameraPositionEnd = new uMap.Position(position);
                    _this.updateCamera();
                }
            }
        },
        cameraDistance           : {
            get: function () {
                var _this = this;
                return _this._cameraDistance;
            },
            set: function (cameraDistance) {
                var _this = this;
                _this._cameraDistance = cameraDistance;
                _this.updateCamera();
            }
        },
        cameraHorizontalViewAngle: {
            get: function () {
                var _this = this;
                return _this._cameraHorizontalViewAngle;
            },
            set: function (cameraHorizontalViewAngle) {
                var _this = this;
                _this._cameraHorizontalViewAngle = cameraHorizontalViewAngle;
                _this.updateCamera();
            }
        },
        cameraVerticalViewAngle  : {
            get: function () {
                var _this = this;
                return _this._cameraVerticalViewAngle;
            },
            set: function (cameraVerticalViewAngle) {
                var _this = this;
                _this._cameraVerticalViewAngle = cameraVerticalViewAngle;
                _this.updateCamera();
            }
        },
        cameraViewHeading        : {
            get: function () {
                var _this = this;
                return _this._cameraViewHeading;
            },
            set: function (cameraViewHeading) {
                var _this = this;
                _this._cameraViewHeading = cameraViewHeading;
                _this.updateCamera();
            }
        },
        cameraViewPitch          : {
            get: function () {
                var _this = this;
                return _this._cameraViewPitch;
            },
            set: function (cameraViewPitch) {
                var _this = this;
                _this._cameraViewPitch = cameraViewPitch;
                _this.updateCamera();
            }
        },
        updateCamera             : {
            value: function () {

                var _this = this;
                var horizontalViewAngle = uEarth.Math.toRadians(_this.cameraHorizontalViewAngle);
                var verticalViewAngle = uEarth.Math.toRadians(_this.cameraVerticalViewAngle);

                _this.camera.frustum.aspectRatio = (Math.tan(horizontalViewAngle / 2) * 2) / (Math.tan(verticalViewAngle / 2) * 2);

                if (horizontalViewAngle > verticalViewAngle) {
                    _this.camera.frustum.fov = horizontalViewAngle;
                } else {
                    _this.camera.frustum.fov = verticalViewAngle;
                }

                _this.updateFrustumOutline();

                _this.camera.setView({
                    destination: _this.cameraPosition.cartesian,
                    orientation: {
                        heading: uEarth.Math.toRadians(_this.cameraViewHeading || 0),
                        pitch  : uEarth.Math.toRadians(_this.cameraViewPitch || 0),
                        roll   : 0
                    }
                });
            }
        },
        createShadowMap          : {
            value: function () {
                var _this = this;
                _this.shadowMap = new uEarth.ShadowMap({
                    context         : (_this.earth.scene).context,
                    lightCamera     : _this.camera,
                    enabled         : _this.enabled,
                    isPointLight    : true,
                    pointLightRadius: _this.cameraDistance,
                    cascadesEnabled : false,
                    size            : _this.size,
                    softShadows     : _this.softShadows,
                    normalOffset    : false,
                    fromLightSource : false
                });
                _this.earth.scene.shadowMap = _this.shadowMap;
            }
        },
        loadVideo                : {
            value: function (callback) {

                var _this = this;
                if (_this.textureUrl) {

                    _this.video = new mhjs.Video({
                        "loop"  : true,
                        "source": [_this.textureUrl]
                    });

                    _this.video.css({
                        "opacity"       : 0,
                        "pointer-events": "none"
                    });

                    $("body").append(_this.video.dom);

                    _this.video.dom[0].oncanplay = function () {

                        _this.textureListener = function () {
                            _this.texture && _this.texture.destroy();
                            _this.texture = new uEarth.Texture({
                                context      : _this.earth.scene.context,
                                source       : _this.video.dom[0],
                                width        : 1,
                                height       : 1,
                                pixelFormat  : uEarth.PixelFormat.RGBA,
                                pixelDatatype: uEarth.PixelDatatype.UNSIGNED_BYTE
                            });
                        };

                        _this.earth.clock.onTick.addEventListener(_this.textureListener);
                        _this.video.dom[0].oncanplay = undefined;

                        callback && callback();

                    };
                }
            }
        },
        loadImage                : {
            value: function (callback) {
                var _this = this;
                if (_this.textureUrl) {

                    var img = new Image();

                    img.onload = function () {
                        _this.texture = new uEarth.Texture({
                            context: _this.earth.scene.context,
                            source : img
                        });

                        callback && callback();
                    };

                    img.onerror = function () {
                        console.log("图片加载失败:" + _this.textureUrl);
                    };
                    img.src = _this.textureUrl;


                }
            }
        },
        loadTexture              : {
            value: function (callback) {

                var _this = this;
                if (_this.textureType !== _class.TEXTURE_TYPE.COLOR) {

                    //视频或图片
                    if (_this.textureType === _class.TEXTURE_TYPE.VIDEO) {
                        _this.currentLoader = _this.loadVideo;
                    } else {
                        _this.currentLoader = _this.loadImage;
                    }

                    _this.currentLoader(function () {
                        callback && callback();
                    });

                } else {
                    //单色
                }
            }
        },
        removeTexture            : {
            value: function () {

                var _this = this;
                if (_this.textureType !== _class.TEXTURE_TYPE.COLOR) {

                    //视频或图片
                    if (_this.textureType === _class.TEXTURE_TYPE.VIDEO) {

                        _this.textureListener && _this.earth.clock.onTick.removeEventListener(_this.textureListener);
                        _this.video && _this.video.remove();


                    } else {

                    }

                } else {
                    //单色
                }
            }
        },
        addPostStageListener     : {
            value: function () {

                var _this = this;

                _this.postStageListener = _this.earth.scene.postProcessStages.add(new uEarth.PostProcessStage({
                    fragmentShader: _this.glsl,
                    uniforms      : {
                        shadowMap_textureCube                                    : function () {
                            _this.shadowMap.update(_this.earth.scene._frameState);
                            return _this.shadowMap._shadowMapTexture;
                        },
                        shadowMap_matrix                                         : function () {
                            _this.shadowMap.update(_this.earth.scene._frameState);
                            return _this.shadowMap._shadowMapMatrix;
                        },
                        shadowMap_lightPositionEC                                : function () {
                            _this.shadowMap.update(_this.earth.scene._frameState);
                            return _this.shadowMap._lightPositionEC;
                        },
                        shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: function () {
                            var bias = _this.shadowMap._pointBias;
                            return uEarth.Cartesian4.fromElements(
                                bias.normalOffsetScale,
                                _this.shadowMap._distance,
                                _this.shadowMap.maximumDistance,
                                0.0,
                                new uEarth.Cartesian4()
                            );
                        },
                        shadowMap_texelSizeDepthBiasAndNormalShadingSmooth       : function () {
                            var bias = _this.shadowMap._pointBias;
                            var scratchTexelStepSize = new uEarth.Cartesian2();
                            var texelStepSize = scratchTexelStepSize;
                            texelStepSize.x = 1.0 / _this.shadowMap._textureSize.x;
                            texelStepSize.y = 1.0 / _this.shadowMap._textureSize.y;

                            return uEarth.Cartesian4.fromElements(
                                texelStepSize.x,
                                texelStepSize.y,
                                bias.depthBias,
                                bias.normalShadingSmooth,
                                new uEarth.Cartesian4()
                            );
                        },
                        camera_projection_matrix                                 : function () {
                            return _this.camera.frustum.projectionMatrix;
                        },
                        camera_view_matrix                                       : function () {
                            return _this.camera.viewMatrix;
                        },
                        helsing_viewDistance                                     : function () {
                            return _this.camera.frustum.far;
                        },
                        helsing_visibleAreaColor                                 : _this.visibleAreaColor,
                        helsing_invisibleAreaColor                               : _this.invisibleAreaColor,
                        helsing_texture                                          : function () {
                            return _this.texture;
                        },
                        helsing_textureType                                      : function () {
                            return _this.textureType;
                        },
                        helsing_alpha                                            : function () {
                            return _this.alpha;
                        }

                    }
                }));
            }
        },
        removePostStageListener  : {
            value: function () {
                var _this = this;
                if (_this.postStageListener && !_this.postStageListener.isDestroyed()) {
                    _this.earth.scene.postProcessStages.remove(_this.postStageListener);
                }
            }
        },
        cameraFrustumOrientation : {
            get: function () {
                var _this = this;
                var scratchRight = new uEarth.Cartesian3();
                var scratchRotation = new uEarth.Matrix3();
                var scratchOrientation = new uEarth.Quaternion();

                var position = _this.camera.positionWC;
                var direction = _this.camera.directionWC;
                var up = _this.camera.upWC;
                var right = _this.camera.rightWC;

                right = uEarth.Cartesian3.negate(right, scratchRight);

                var rotation = scratchRotation.clone();

                uEarth.Matrix3.setColumn(rotation, 0, right, rotation);
                uEarth.Matrix3.setColumn(rotation, 1, up, rotation);
                uEarth.Matrix3.setColumn(rotation, 2, direction, rotation);

                var orientation = uEarth.Quaternion.fromRotationMatrix(rotation, scratchOrientation);

                return orientation;
            }
        },
        addFrustumOutline        : {
            value: function () {

                var _this = this;

                _this.frustumOutlineInstance = new uEarth.GeometryInstance({
                    geometry  : new uEarth.FrustumOutlineGeometry({
                        frustum    : _this.camera.frustum,
                        origin     : _this.camera.position,
                        orientation: _this.cameraFrustumOrientation
                    }),
                    id        : Math.random().toString(36).substr(2),
                    attributes: {
                        color: uEarth.ColorGeometryInstanceAttribute.fromColor(
                            uEarth.Color.YELLOW//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
                        ),
                        show : new uEarth.ShowGeometryInstanceAttribute(true)
                    }
                });

                _this.frustumOutline = _this.earth.scene.primitives.add(new uEarth.Primitive({
                    geometryInstances       : _this.frustumOutlineInstance,
                    releaseGeometryInstances: false,
                    appearance              : new uEarth.PerInstanceColorAppearance({
                        flat       : true,
                        translucent: false
                    })
                }));


            }
        },
        updateFrustumOutline     : {
            value: function () {
                var _this = this;
                if (_this.frustumOutline && !_this.frustumOutline.isDestroyed()) {
                    _this.removeFrustumOutline();
                    _this.addFrustumOutline();
                }
            }
        },
        removeFrustumOutline     : {
            value: function () {
                var _this = this;
                if (_this.frustumOutline && !_this.frustumOutline.isDestroyed()) {
                    _this.earth.scene.primitives.remove(_this.frustumOutline);
                }
            }
        },
        drawSketch               : {
            value: function () {

                var _this = this;

                _this.sketch = _this.earth.entities.add({
                    name       : "sketch",
                    position   : _this.cameraPosition.cartesian,
                    orientation: uEarth.Transforms.headingPitchRollQuaternion(
                        _this.cameraPosition.cartesian,
                        uEarth.HeadingPitchRoll.fromDegrees(_this.cameraViewHeading - 90, _this.cameraViewPitch, 0.0)
                    ),
                    ellipsoid  : {
                        radii          : new uEarth.Cartesian3(
                            _this.cameraDistance,
                            _this.cameraDistance,
                            _this.cameraDistance
                        ),
                        // innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
                        minimumClock   : uEarth.Math.toRadians(-_this.cameraHorizontalViewAngle / 2),
                        maximumClock   : uEarth.Math.toRadians(_this.cameraHorizontalViewAngle / 2),
                        minimumCone    : uEarth.Math.toRadians(90 - _this.cameraVerticalViewAngle / 2),
                        maximumCone    : uEarth.Math.toRadians(90 + _this.cameraVerticalViewAngle / 2),
                        fill           : false,
                        outline        : true,
                        subdivisions   : 256,
                        stackPartitions: 64,
                        slicePartitions: 64,
                        outlineColor   : uEarth.Color.YELLOW
                    }
                });
            }
        }
    });

    Object.defineProperties(_class, {
        TEXTURE_TYPE: {
            get: function () {
                return {
                    "VIDEO": 1,
                    "IMAGE": 2,
                    "COLOR": 3
                };
            }
        }
    });

    mhjs.EventInterface(_class);

    return _class;

});